#pragma once

#include <compl.h>
#include <dbg.h>
#include <dinfra/list.h>

#ifndef ARRCACHE_STATIC_MAX_NR
	#define ARRCACHE_STATIC_MAX_NR (63)
#endif
#define ARRCACHE_SIZE	(sizeof(word_t) + ARRCACHE_STATIC_MAX_NR * sizeof(void *))
typedef struct
{
	hword_t cached_nr;
	hword_t cached_max_nr;
	void *cached_ptrs[];
} arrcache_t;

typedef struct
{
	union{
		slist_t *next;
		size_t nr;
	};
} skplist_node_t;

typedef struct
{
	slist_t *next;
	skplist_node_t *skip_tail;
} skplist_t;

#define ARRCACHE_USE_SKIPLIST

SAI arrcache_t *arrcache_init(void *mem, size_t size, hword_t cached_max_nr)
{	
	ASSERT(size >= sizeof(arrcache_t) + cached_max_nr * sizeof(void *));
	arrcache_t *cache = (arrcache_t *)mem;
	cache->cached_max_nr = cached_max_nr;
	cache->cached_nr = 0;
	// __memset(&cache->cached_ptrs[0], 0, cached_max_nr * sizeof(void *));
	return cache;
}

SAI bool_t arrcache_push_batch(arrcache_t *cache, slist_t *head, slist_t *tail, size_t nr)
{
#ifndef ARRCACHE_USE_SKIPLIST
	if (cache->cached_nr + nr <= cache->cached_max_nr)
	{

		// 出来后连接最后一个节点
		// 可能会溢出但是问题不大
		tail->next = cache->cached_ptrs[cache->cached_nr - 1];
		// decho("corecache", "free batch, free size %lu, limit_size %lu\n", nr * size, cc->limit_size);
		for (hsword_t i = 0; i < nr; i++)
		{
			// 倒过来连接
			cache->cached_ptrs[cache->cached_nr + nr - 1 - i] = head;
			// 假设已经连接好了，不需要连接
			head = head->next;
		}
		cache->cached_nr += nr;
		return TRUE;
	}

#else
	if (cache->cached_nr < cache->cached_max_nr)
	{
		skplist_node_t *ttail = (skplist_node_t *)tail;
		skplist_t *thead = (skplist_t *)head;

		thead->skip_tail = ttail;
		tail->next = NULL;
		// ASSERT(slist_len_noloop(head) == nr);
		ttail->nr = nr;
		// ASSERT(cache->cached_ptrs[cache->cached_nr] == NULL_PTR);
		cache->cached_ptrs[cache->cached_nr++] = head;
		
		ASSERT(cache->cached_nr <= cache->cached_max_nr);
		return TRUE;
	}
#endif
	return FALSE;
}

// ! 可能有问题
SAI size_t arrcache_pop_batch(arrcache_t *cache, slist_t **head, slist_t **tail, size_t expect_nr)
{
	if (cache->cached_nr == 0)
		return 0;
#ifndef ARRCACHE_USE_SKIPLIST
	if (expect_nr > cache->cached_nr)
		expect_nr = cache->cached_nr;
	// if (cache->cached_nr == 0) return 0;
	decho("arrcache", "expect_nr %d\n", expect_nr);
	slist_t *thead = (slist_t *)cache->cached_ptrs[cache->cached_nr - 1];
	slist_t *tcur = thead;
	// slist_t *tnext;
	hsword_t i;

	// 直接获得尾部，因为默认是已经连接的
	i = expect_nr;
	tcur = (slist_t *)cache->cached_ptrs[cache->cached_nr - i];
	/*
	for(i = 1; i < expect_nr; i++){
		// 超过上限
		// if(i >= cache->cached_nr) break;
		tnext = (slist_t *)cache->cached_ptrs[cache->cached_nr - 1 - i];
		tcur->next = tnext;
		tcur = tnext;
	}*/
	// slist_t *tmp = thead;

	cache->cached_nr = cache->cached_nr - i;
	*head = thead;
	*tail = tcur;

	return (hword_t)i;
#else
	ASSERT(cache->cached_nr >= 1);
	size_t real_poped = 0;
	skplist_t *thead = (skplist_t *)cache->cached_ptrs[--cache->cached_nr];
	// cache->cached_ptrs[cache->cached_nr] = NULL_PTR;
	// skplist_t *tcur;
	skplist_node_t *ttail = thead->skip_tail;
	real_poped += ttail->nr;


	skplist_t *tcur;
	skplist_node_t *tcurtail;
	
	while((real_poped < expect_nr) && (cache->cached_nr > 0)){
		tcur = (skplist_t *)cache->cached_ptrs[--cache->cached_nr];
		// cache->cached_ptrs[cache->cached_nr] = NULL_PTR;
		tcurtail = tcur->skip_tail;
		size_t tcur_nr = tcurtail->nr;
		real_poped += tcur_nr;
		
		/* 检查长度是否符合 */
		// tcurtail->next = NULL;
		// ASSERT(slist_len_noloop((slist_t *)tcur) == tcur_nr);

		/* 当前ttail连接到tcur */
		ttail->next = (slist_t *)tcur;
		ttail = tcurtail;
	}
	ttail->next = NULL;
	// ASSERT(slist_len_noloop((slist_t *)thead) == real_poped);
	*head = (slist_t *)thead;
	*tail = (slist_t *)ttail;
	// ASSERT(cache->cached_nr > 0);
	return real_poped;
#endif
}